/**
* This file is part of mobileworks.
*
* mobileworks is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* You should have received a copy of the GNU General Public License
* along with dev.clipall.  If not, see <http://www.gnu.org/licenses/>.
*
* https://code.google.com/p/mobileworks/
*/

package gml;

import gml.xsd.Gml;
import gml.xsd.Gml.Pages.Page;
import gml.xsd.Gml.Pages.Page.Component;
import gml.xsd.Gml.Pages.Page.Menu;
import gml.xsd.Gml.Pages.Page.Menu.Command;
import gml.xsd.Gml.States.State;
import gml.xsd.Gml.States.State.Action;
import gml.xsd.Gml.States.State.Action.Param;
import gml.xsd.Gml.States.State.Transition;
import gml.xsd.Gml.Styles.Style;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;

/**
 *
 * @author Erol Hira
 */
public class Main implements Constants {
    
    private Fsm fsm;
    
    public Main(){
        
        fsm = new Fsm();
        
        try {
            test();
        } catch (Exception ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    public static void main(String[] args) {
        
        new Main();
    }   

    private void test() throws Exception {
        
        // gml.xsd is the package in which binding classes are generated
        JAXBContext jc = JAXBContext.newInstance("gml.xsd");
            
        Unmarshaller u = jc.createUnmarshaller();
        
        Gml gml = (Gml) u.unmarshal(
                    Main.class.getResourceAsStream("/test.xml"));
        
        addStyles(gml);
        addPages(gml);
        addStates(gml);
        
        fsm.setArrays();
        
        new Packer(fsm).pack();
    }
    
    private void addStates(Gml gml){
        
        addAllStates(gml);
        
        List<State> states = gml.getStates().getState();
        
        int[][][] stateArr = new int[states.size()][3][]; // 0.page 1.transition 2.action
        
        int stateIndex = 0;
        for(State state : states){                        
            
            // add page
            stateArr[stateIndex][0] = new int[1];            
            stateArr[stateIndex][0][0] = fsm.getPageIdIndex(state.getPage());
                                    
            // add transitions
            List<Transition> transitions = state.getTransition();
            
            stateArr[stateIndex][1] = new int[transitions.size()];
            
            int transIndex = 0;
            for(Transition trans : transitions){
                
                ArrayList<Integer> transition = new ArrayList<Integer>();
                transition.add(fsm.addTransitionId(trans.getEvent()));                
                transition.add(fsm.getStateIdIndex(trans.getState()));
                
                stateArr[stateIndex][1][transIndex] = fsm.addTransition(transition);
                
                transIndex ++;
            }
            
            // add actions
            List<Action> actions = state.getAction();
            
            stateArr[stateIndex][2] = new int[actions.size()];
            
            int actionIndex = 0;
            for(Action action : actions){
                
                ArrayList<Integer> act = new ArrayList<Integer>();
                act.add(fsm.addActionId(action.getEvent()));
                
                ArrayList<String> function = new ArrayList<String>();
                function.add(action.getAction());
                for(Param param : action.getParam()){
                    function.add(param.getValue());
                }
                
                act.add(fsm.addFunction(function));
                
                stateArr[stateIndex][2][actionIndex] = fsm.addAction(act);
                
                actionIndex ++;
            }
            
            stateIndex ++;
        }
        
        fsm.setStates(stateArr);
    }
    
    private void addAllStates(Gml gml){
        
        List<State> states = gml.getStates().getState();
        
        int stateIndex = 0;
        for(State state : states){
            
            fsm.addToStateIdMap(state.getId(), stateIndex);
        
            stateIndex ++;
        }
    }
    
    private void addPages(Gml gml){
        
        List<Page> pages = gml.getPages().getPage();
        
        int[][][][] pageArr = new int[pages.size()][2][][];
        
        int pageIndex = 0;
        for(Page page : pages){
            
            fsm.addToPageIdMap(page.getId(), pageIndex);
            
            List<Component> comps = page.getComponent();
            
            int[][] compArr = new int[comps.size()][];
            
            int compIndex = 0;
            for(Component comp : comps){
                
                compArr[compIndex] = new int[comp.getProperty().size() + 1];
                
                String style = comp.getStyle();
                int styleId = -1;
                if(style != null){
                    styleId = fsm.getStyleIdIndex(style);
                }
                
                compArr[compIndex][0] = styleId;
                
                List<gml.xsd.Gml.Pages.Page.Component.Property> props = comp.getProperty();
                
                int propIndex = 1;
                for(gml.xsd.Gml.Pages.Page.Component.Property prop : props){
                    
                    ArrayList<Integer> p = new ArrayList<Integer>();
                    p.add(fsm.getPropertyId(prop.getName()));
                    fsm.addPropValue(p, prop.getName(), prop.getValue());
                    
                    int pIndex = fsm.addProperty(p);

                    compArr[compIndex][propIndex] = pIndex;
                    
                    propIndex ++;
                }
                
                compIndex ++;
            }
            
            pageArr[pageIndex][0] = compArr;
            
            //
            
            List<Menu> menus = page.getMenu();
            
            int[][] menuArr = new int[menus.size()][];
            
            int menuIndex = 0;
            for(Menu menu : menus){
                
                
                menuArr[menuIndex] = new int[menu.getCommand().size() + 1]; // 1 for position info
                
                menuArr[menuIndex][0] = getMenuPosition(menu.getPosition());
                
                List<Command> commands = menu.getCommand();
                
                int commandIndex = 1;
                for(Command command : commands){
                    
                    ArrayList<Integer> p = new ArrayList<Integer>();
                    p.add(fsm.addCommandId(command.getId()));
                    p.add(fsm.makeString(command.getEvent()));

                    int pIndex = fsm.addCommand(p);

                    menuArr[menuIndex][commandIndex] = pIndex;
                    
                    commandIndex ++;
                }
                
                menuIndex ++;
            }
            
            pageArr[pageIndex][1] = menuArr;
            
            pageIndex ++;
        }
        
        fsm.setPages(pageArr);
    }
    
    private void addStyles(Gml gml) {
        
        List<Style> styles = gml.getStyles().getStyle();
        
        int[][] styleArr = new int[styles.size()][];
                
        int styleIndex = 0;
        for(Style style : styles){
            
            fsm.addToStyleIdMap(style.getId(), styleIndex);
            
            List<gml.xsd.Gml.Styles.Style.Property> props = style.getProperty();
            
            styleArr[styleIndex] = new int[props.size()];
            
            int pIndex = 0;
            for(gml.xsd.Gml.Styles.Style.Property p : props){
                
                //System.out.println("style" + pIndex + " prop " + p.getName() + ": " + p.getValue());
                
                ArrayList<Integer> prop = new ArrayList<Integer>();
                prop.add(fsm.getPropertyId(p.getName()));
                prop.add(Integer.parseInt(p.getValue()));
                
                int propIndex = fsm.addProperty(prop);
                
                styleArr[styleIndex][pIndex] = propIndex;
                
                pIndex ++;
            }
            
            styleIndex ++;
        }
        
        fsm.setStyles(styleArr);
    }

    public int getMenuPosition(String positionString){
        
        if(MenuPositions.LEFT_STR.equals(positionString)){
            return MenuPositions.LEFT;
        } else if(MenuPositions.RIGHT_STR.equals(positionString)){
            return MenuPositions.RIGHT;
        } else if(MenuPositions.CENTER_STR.equals(positionString)){
            return MenuPositions.CENTER;
        } else {
            return -1;
        }
    }
    
}
